﻿/* Copyright (c) 2008, 2009, John Cronin
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *     * Redistributions of source code must retain the above copyright
 *       notice, this list of conditions and the following disclaimer.
 *     * Redistributions in binary form must reproduce the above copyright
 *       notice, this list of conditions and the following disclaimer in the
 *       documentation and/or other materials provided with the distribution.
 *     * Neither the name of the copyright holder nor the
 *       names of its contributors may be used to endorse or promote products
 *       derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY
 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */

using System;
using System.Collections.Generic;
using System.Text;

namespace tysila
{
    enum LabelType
    {
        Function,
        Object,
        AddressOf,
        DataSectionPointer,
        FunctionPointerFromData
    }

    class OutputBlock
    {
    }

    class NodeReference : OutputBlock
    {
        public int block_id;
        public int length;
        public int offset;

        public int longest_distance;

        public bool IsPossible
        {
            get
            {
                switch (length)
                {
                    case 1:
                        if ((longest_distance >= SByte.MinValue) && (longest_distance <= SByte.MaxValue))
                            return true;
                        return false;
                    case 2:
                        if ((longest_distance >= Int16.MinValue) && (longest_distance <= Int16.MaxValue))
                            return true;
                        return false;
                    case 4:
                        if ((longest_distance >= Int32.MinValue) && (longest_distance <= Int32.MaxValue))
                            return true;
                        return false;
                    case 8:
                        return true;
                    default:
                        throw new NotSupportedException();
                }
            }
        }
    }

    class NodeHeader : OutputBlock
    {
        public int block_id;
    }

    class BlockChoice : OutputBlock
    {
        public IList<IList<OutputBlock>> Choices;
    }

    class CodeBlock : OutputBlock
    {
        public IList<byte> Code;

        public class CompiledInstruction
        {
            protected CompiledInstruction() { }
            public CompiledInstruction(string inst) { _inst = inst; }
            string _inst = null;

            public override string ToString()
            {
                if (_inst == null)
                    return "";
                else
                    return _inst;
            }

            public virtual IList<byte> GetCompiledRepresentation() { return new byte[] { }; }
        }

        public IList<CompiledInstruction> Instructions;

        public CodeBlock() { }
        public CodeBlock(IList<byte> v1) { Code = v1; }
        public CodeBlock(IList<byte> v1, IList<byte> v2) { Code = new List<byte>(v1); ((List<byte>)Code).AddRange(v2); }
        public CodeBlock(IList<byte> v1, IList<CompiledInstruction> instrs) : this(v1) { Instructions = instrs; }
        public CodeBlock(IList<byte> v1, CompiledInstruction instr) : this(v1) { Instructions = new CompiledInstruction[] { instr }; }
        public CodeBlock(IList<byte> v1, IList<byte> v2, IList<CompiledInstruction> instrs) : this(v1, v2) { Instructions = instrs; }
    }

    class DataBlock : OutputBlock
    {
        public byte[] Data;

        public bool ReadOnly = true;

        public DataBlock(byte[] data) { Data = data; }
        public DataBlock(byte[] data, bool read_only) { Data = data; ReadOnly = read_only; }
        public DataBlock() { }
    }

    class ExportedSymbol : OutputBlock
    {
        public string Name;

        public ExportedSymbol(String name) { Name = name; }
    }

    public enum SymbolDescribes { text, data, rodata };

    class RelocationBlock : OutputBlock
    {
        public int Size = 4;

        public uint RelType;
        public string Target;

        public int Offset;
        public int Value;
    }
}
